﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using UCS.XNA.Utils.Animation;

namespace UCS.XNA.Utils
{
    public class Border : IDrawable, IFadeAnimatable
    {
        #region Constants

        private const float ANGLE_90_DEGREES_IN_RADIANS = (float)System.Math.PI * 90f / 180f;
        private const float ANGLE_180_DEGREES_IN_RADIANS = (float)System.Math.PI * 180f / 180f;
        private const float ANGLE_270_DEGREES_IN_RADIANS = (float)System.Math.PI * 270f / 180f;

        #endregion

        #region Attributes and Properties

        private Texture2D _cornerTexture;
        public Texture2D CornerTexture
        {
            get { return this._cornerTexture; }
            set { this._cornerTexture = value; }
        }

        private Texture2D _borderTexture;
        public Texture2D BorderTexture
        {
            get { return this._borderTexture; }
            set { this._borderTexture = value; }
        }

        private Rectangle _bounds;
        public Rectangle Bounds
        {
            get { return this._bounds; }
            set
            {
                this._bounds = value;

                this.InitializeCornersBounds();
                this.InitializeBordersBounds();
            }
        }

        private float _transparency;
        public float Transparency
        {
            get { return this._transparency; }
            set { this._transparency = value; }
        }

        public int DrawOrder
        {
            get { throw new NotImplementedException(); }
        }

        private bool _visible;
        public bool Visible
        {
            get { return this._visible; }
            set { this._visible = value; }
        }

        #endregion

        #region Private Members

        private Rectangle _topLeftCornerBounds;
        private Rectangle _topRightCornerBounds;
        private Rectangle _bottomRightCornerBounds;
        private Rectangle _bottomLeftCornerBounds;
        private Rectangle _topBorderBounds;
        private Rectangle _rightBorderBounds;
        private Rectangle _bottomBorderBounds;
        private Rectangle _leftBorderBounds;
        private FadeAnimation _fadeAnimation;

        #endregion

        #region Events

        public event EventHandler<EventArgs> DrawOrderChanged;
        public event EventHandler<EventArgs> VisibleChanged;

        #endregion

        #region Constructors

        public Border(Texture2D cornerTexture, Texture2D borderTexture)
        {
            this._cornerTexture = cornerTexture;
            this._borderTexture = borderTexture;
            this._transparency = 1;

            this.InitializeCornersBounds();
            this.InitializeBordersBounds();
        }

        #endregion

        #region Private Methods

        private void InitializeCornersBounds()
        {
            this._topLeftCornerBounds.X = this._bounds.X;
            this._topLeftCornerBounds.Y = this._bounds.Y;
            this._topLeftCornerBounds.Width = this._cornerTexture.Width;
            this._topLeftCornerBounds.Height = this._cornerTexture.Height;

            this._topRightCornerBounds.X = this._bounds.X + this._bounds.Width;
            this._topRightCornerBounds.Y = this._bounds.Y;
            this._topRightCornerBounds.Width = this._cornerTexture.Width;
            this._topRightCornerBounds.Height = this._cornerTexture.Height;

            this._bottomRightCornerBounds.X = this._bounds.X + this._bounds.Width;
            this._bottomRightCornerBounds.Y = this._bounds.Y + this._bounds.Height;
            this._bottomRightCornerBounds.Width = this._cornerTexture.Width;
            this._bottomRightCornerBounds.Height = this._cornerTexture.Height;

            this._bottomLeftCornerBounds.X = this._bounds.X;
            this._bottomLeftCornerBounds.Y = this._bounds.Y + this._bounds.Height;
            this._bottomLeftCornerBounds.Width = this._cornerTexture.Width;
            this._bottomLeftCornerBounds.Height = this._cornerTexture.Height;
        }

        private void InitializeBordersBounds()
        {
            this._topBorderBounds.X = this._bounds.X + this._cornerTexture.Width;
            this._topBorderBounds.Y = this._bounds.Y;
            this._topBorderBounds.Width = this._bounds.Width - 2 * this._cornerTexture.Width;
            this._topBorderBounds.Height = this._borderTexture.Height;

            this._rightBorderBounds.X = this._bounds.X + this._bounds.Width;
            this._rightBorderBounds.Y = this._bounds.Y + this._cornerTexture.Height;
            this._rightBorderBounds.Width = this._bounds.Height - 2 * this._cornerTexture.Height;
            this._rightBorderBounds.Height = this._borderTexture.Height;

            this._bottomBorderBounds.X = this._bounds.X + this._cornerTexture.Width;
            this._bottomBorderBounds.Y = this._bounds.Y + this._bounds.Height - this._cornerTexture.Height;
            this._bottomBorderBounds.Width = this._bounds.Width - 2 * this._cornerTexture.Width;
            this._bottomBorderBounds.Height = this._borderTexture.Height;

            this._leftBorderBounds.X = this._bounds.X + this.CornerTexture.Width;
            this._leftBorderBounds.Y = this._bounds.Y + this._cornerTexture.Height;
            this._leftBorderBounds.Width = this._bounds.Height - 2 * this._cornerTexture.Height;
            this._leftBorderBounds.Height = this._borderTexture.Height;
        }

        private void DrawCorners()
        {
            SpriteBatch spriteBatch = GameResources.SpriteBatch;

            spriteBatch.Draw(this._cornerTexture, this._topLeftCornerBounds, null, Color.White * this._transparency, 0f, Vector2.Zero, SpriteEffects.None, 0);
            spriteBatch.Draw(this._cornerTexture, this._topRightCornerBounds, null, Color.White * this._transparency, ANGLE_90_DEGREES_IN_RADIANS, Vector2.Zero, SpriteEffects.None, 0);
            spriteBatch.Draw(this._cornerTexture, this._bottomRightCornerBounds, null, Color.White * this._transparency, ANGLE_180_DEGREES_IN_RADIANS, Vector2.Zero, SpriteEffects.None, 0);
            spriteBatch.Draw(this._cornerTexture, this._bottomLeftCornerBounds, null, Color.White * this._transparency, ANGLE_270_DEGREES_IN_RADIANS, Vector2.Zero, SpriteEffects.None, 0);
        }

        private void DrawBorders()
        {
            SpriteBatch spriteBatch = GameResources.SpriteBatch;

            spriteBatch.Draw(this._borderTexture, this._topBorderBounds, Color.White * this._transparency);
            spriteBatch.Draw(this._borderTexture, this._rightBorderBounds, null, Color.White * this._transparency, ANGLE_90_DEGREES_IN_RADIANS, Vector2.Zero, SpriteEffects.None, 0);
            spriteBatch.Draw(this._borderTexture, this._bottomBorderBounds, null, Color.White * this._transparency, 0f, Vector2.Zero, SpriteEffects.FlipVertically, 0);
            spriteBatch.Draw(this._borderTexture, this._leftBorderBounds, null, Color.White * this._transparency, ANGLE_90_DEGREES_IN_RADIANS, Vector2.Zero, SpriteEffects.FlipVertically, 0);
        }

        #endregion

        #region Public Methods

        public void Update(GameTime gameTime)
        {
            if (this._fadeAnimation != null)
                this._fadeAnimation.Update(gameTime);
        }

        public void Draw(GameTime gameTime)
        {
            GameResources.SpriteBatch.Begin();

            this.DrawCorners();
            this.DrawBorders();

            GameResources.SpriteBatch.End();
        }

        public void Hide()
        {
            this._fadeAnimation = new FadeOutAnimation(this, 0.05f);
            this._fadeAnimation.AnimationFinished += (sender, e) => { this._visible = false; };
        }

        public void Show()
        {
            this._visible = true;
            this._fadeAnimation = new FadeInAnimation(this, 0.05f);
        }

        #endregion
    }
}
